home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / utilit~1 / futilsrc.zoo / fileutil / src / chown.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-27  |  8.2 KB  |  364 lines

  1. /* chown -- change user and group ownership of files
  2.    Copyright (C) 1989-1991 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* 
  19.               |                   user
  20.               | unchanged                 explicit
  21.  -------------|-------------------------+-------------------------|
  22.  g unchanged  | ---                     | chown u           |
  23.  r            |-------------------------+-------------------------|
  24.  o explicit   | chgrp g or chown .g     | chown u.g          |
  25.  u            |-------------------------+-------------------------|
  26.  p from passwd| ---                  | chown u.             |
  27.               |-------------------------+-------------------------|
  28.  
  29.    Written by David MacKenzie <djm@ai.mit.edu>. */
  30.  
  31. #include <stdio.h>
  32. #include <ctype.h>
  33. #include <sys/types.h>
  34. #include <pwd.h>
  35. #include <grp.h>
  36. #include <getopt.h>
  37. #include "system.h"
  38.  
  39. #ifndef POSIX
  40. struct passwd *getpwnam ();
  41. struct group *getgrnam ();
  42. void endpwent ();
  43. void endgrent ();
  44. #endif
  45.  
  46. int lstat ();
  47. int stat ();
  48.  
  49. char *savedir ();
  50. char *xmalloc ();
  51. char *xrealloc ();
  52. int change_file_owner ();
  53. int change_dir_owner ();
  54. int isnumber ();
  55. void describe_change ();
  56. void error ();
  57. void parse_owner ();
  58. void usage ();
  59.  
  60. /* The name the program was run with. */
  61. char *program_name;
  62.  
  63. /* If nonzero, change the ownership of directories recursively. */
  64. int recurse;
  65.  
  66. /* If nonzero, force silence (no error messages). */
  67. int force_silent;
  68.  
  69. /* If nonzero, describe the files we process. */
  70. int verbose;
  71.  
  72. /* If nonzero, describe only owners or groups that change. */
  73. int changes_only;
  74.  
  75. /* A pointer to either lstat or stat. */
  76. int (*xstat) ();
  77.  
  78. /* The name of the user to which ownership of the files is being given. */
  79. char *username;
  80.  
  81. /* The name of the group to which ownership of the files is being given. */
  82. char *groupname;
  83.  
  84. struct option long_options[] =
  85. {
  86.   {"dereference", 0, 0, 'L'},
  87.   {"recursive", 0, 0, 'R'},
  88.   {"show-changes", 0, 0, 'c'},
  89.   {"silent", 0, 0, 'f'},
  90.   {"quiet", 0, 0, 'f'},
  91.   {"verbose", 0, 0, 'v'},
  92.   {0, 0, 0, 0}
  93. };
  94.  
  95. void
  96. main (argc, argv)
  97.      int argc;
  98.      char **argv;
  99. {
  100.   int user = -1;        /* New uid; -1 if not to be changed. */
  101.   int group = -1;        /* New gid; -1 if not to be changed. */
  102.   int errors = 0;
  103.   int optc;
  104.  
  105.   program_name = argv[0];
  106.   recurse = force_silent = verbose = changes_only = 0;
  107.   xstat = lstat;
  108.  
  109.   while ((optc = getopt_long (argc, argv, "LRcfv", long_options, (int *) 0))
  110.      != EOF)
  111.     {
  112.       switch (optc)
  113.     {
  114.     case 'L':
  115.       xstat = stat;
  116.       break;
  117.     case 'R':
  118.       recurse = 1;
  119.       break;
  120.     case 'c':
  121.       verbose = 1;
  122.       changes_only = 1;
  123.       break;
  124.     case 'f':
  125.       force_silent = 1;
  126.       break;
  127.     case 'v':
  128.       verbose = 1;
  129.       break;
  130.     default:
  131.       usage ();
  132.     }
  133.     }
  134.  
  135.   if (optind >= argc - 1)
  136.     usage ();
  137.  
  138.   parse_owner (argv[optind++], &user, &group);
  139.  
  140.   for (; optind < argc; ++optind)
  141.     errors |= change_file_owner (argv[optind], user, group);
  142.  
  143.   exit (errors);
  144. }
  145.  
  146. /* Set *U and *G according to NAME. */
  147.  
  148. void
  149. parse_owner (name, u, g)
  150.      char *name;
  151.      int *u, *g;
  152. {
  153.   struct passwd *pwd;
  154.   struct group *grp;
  155.   char *cp;
  156.   int use_login_group = 0;
  157.  
  158.   /* Check whether group is given. */
  159.   cp = index (name, ':');
  160.   if (cp == NULL)
  161.     cp = index (name, '.');
  162.   if (cp != NULL)
  163.     {
  164.       *cp++ = '\0';
  165.       groupname = cp;
  166.       if (*cp == '\0')
  167.     {
  168.       if (cp == name + 1)
  169.         /* Neither user nor group given, just '.'. */
  170.         error (1, 0, "can not omit both user and group");
  171.       else
  172.         use_login_group = 1;
  173.     }
  174.       else
  175.     {
  176.       grp = getgrnam (cp);
  177.       if (grp == NULL)
  178.         {
  179.           if (!isnumber (cp))
  180.         error (1, 0, "invalid group `%s'", cp);
  181.           *g = atoi (cp);
  182.         }
  183.       else
  184.         *g = grp->gr_gid;
  185.       endgrent ();        /* Save a file descriptor. */
  186.     }
  187.     }
  188.  
  189.   /* Parse user. */
  190.   username = name;
  191.   groupname = 0;
  192.   if (name[0] != '\0')
  193.     {
  194.       pwd = getpwnam (name);
  195.       if (pwd == NULL)
  196.     {
  197.       if (!isnumber (name))
  198.         error (1, 0, "invalid user `%s'", name);
  199.       if (use_login_group)
  200.         error (1, 0, "cannot get login group for numeric UID");
  201.       *u = atoi (name);
  202.     }
  203.       else
  204.     {
  205.       *u = pwd->pw_uid;
  206.       if (use_login_group)
  207.         {
  208.           *g = pwd->pw_gid;
  209.           grp = getgrgid (pwd->pw_gid);
  210.           if (grp == NULL)
  211.         {
  212.           groupname = xmalloc (15);
  213.           sprintf (groupname, "%u", pwd->pw_gid);
  214.         }
  215.           else
  216.         groupname = grp->gr_name;
  217.           endgrent ();
  218.         }
  219.     }
  220.       endpwent ();
  221.     }
  222. }
  223.  
  224. /* Change the ownership of FILE to UID USER and GID GROUP.
  225.    If it is a directory and -R is given, recurse.
  226.    Return 0 if successful, 1 if errors occurred. */
  227.  
  228. int
  229. change_file_owner (file, user, group)
  230.      char *file;
  231.      int user, group;
  232. {
  233.   struct stat file_stats;
  234.   int newuser, newgroup;
  235.   int errors = 0;
  236.  
  237.   if ((*xstat) (file, &file_stats))
  238.     {
  239.       if (force_silent == 0)
  240.     error (0, errno, "%s", file);
  241.       return 1;
  242.     }
  243. #ifdef S_ISLNK
  244.   if (S_ISLNK (file_stats.st_mode))
  245.     return 0;
  246. #endif
  247.  
  248.   newuser = user == -1 ? file_stats.st_uid : user;
  249.   newgroup = group == -1 ? file_stats.st_gid : group;
  250.   if (newuser != file_stats.st_uid || newgroup != file_stats.st_gid)
  251.     {
  252.       if (verbose)
  253.     describe_change (file, 1);
  254.       if (chown (file, newuser, newgroup))
  255.     {
  256.       if (force_silent == 0)
  257.         error (0, errno, "%s", file);
  258.       errors = 1;
  259.     }
  260.     }
  261.   else if (verbose && changes_only == 0)
  262.     describe_change (file, 0);
  263.  
  264.   if (recurse && S_ISDIR (file_stats.st_mode))
  265.     errors |= change_dir_owner (file, user, group, &file_stats);
  266.   return errors;
  267. }
  268.  
  269. /* Recursively change the ownership of the files in directory DIR
  270.    to UID USER and GID GROUP.
  271.    STATP points to the results of lstat or stat on DIR.
  272.    Return 0 if successful, 1 if errors occurred. */
  273.  
  274. int
  275. change_dir_owner (dir, user, group, statp)
  276.      char *dir;
  277.      int user, group;
  278.      struct stat *statp;
  279. {
  280.   char *name_space, *namep;
  281.   char *path;            /* Full path of each entry to process. */
  282.   unsigned dirlength;        /* Length of `dir' and '\0'. */
  283.   unsigned filelength;        /* Length of each pathname to process. */
  284.   unsigned pathlength;        /* Bytes allocated for `path'. */
  285.   int errors = 0;
  286.  
  287.   errno = 0;
  288.   name_space = savedir (dir, statp->st_size);
  289.   if (name_space == NULL)
  290.     {
  291.       if (errno)
  292.     {
  293.       if (force_silent == 0)
  294.         error (0, errno, "%s", dir);
  295.       return 1;
  296.     }
  297.       else
  298.     error (1, 0, "virtual memory exhausted");
  299.     }
  300.  
  301.   dirlength = strlen (dir) + 1;    /* + 1 is for the trailing '/'. */
  302.   pathlength = dirlength + 1;
  303.   /* Give `path' a dummy value; it will be reallocated before first use. */
  304.   path = xmalloc (pathlength);
  305.   strcpy (path, dir);
  306.   path[dirlength - 1] = '/';
  307.  
  308.   for (namep = name_space; *namep; namep += filelength - dirlength)
  309.     {
  310.       filelength = dirlength + strlen (namep) + 1;
  311.       if (filelength > pathlength)
  312.     {
  313.       pathlength = filelength * 2;
  314.       path = xrealloc (path, pathlength);
  315.     }
  316.       strcpy (path + dirlength, namep);
  317.       errors |= change_file_owner (path, user, group);
  318.     }
  319.   free (path);
  320.   free (name_space);
  321.   return errors;
  322. }
  323.  
  324. /* Tell the user the user and group names to which ownership of FILE
  325.    has been given; if CHANGED is zero, FILE had those owners already. */
  326.  
  327. void
  328. describe_change (file, changed)
  329.      char *file;
  330.      int changed;
  331. {
  332.   if (changed)
  333.     printf ("owner of %s changed to ", file);
  334.   else
  335.     printf ("owner of %s retained as ", file);
  336.   if (groupname)
  337.     printf ("%s.%s\n", username, groupname);
  338.   else
  339.     printf ("%s\n", username);
  340. }
  341.  
  342. /* Return nonzero if STR represents an unsigned decimal integer,
  343.    otherwise return 0. */
  344.  
  345. int
  346. isnumber (str)
  347.      char *str;
  348. {
  349.   for (; *str; str++)
  350.     if (!isdigit (*str))
  351.       return 0;
  352.   return 1;
  353. }
  354.  
  355. void
  356. usage ()
  357. {
  358.   fprintf (stderr, "\
  359. Usage: %s [-LRcfv] [+recursive] [+show-changes] [+dereference]\n\
  360.        [+silent] [+quiet] [+verbose] [user][:.][group] file...\n",
  361.        program_name);
  362.   exit (1);
  363. }
  364.